package jwt

import (
	"errors"
	"gin_server/config"
	"gin_server/internal/model"
	"time"

	"github.com/golang-jwt/jwt/v4"
)

// AccessClaims 自定义JWT声明结构体
type AccessClaims struct {
	SelfAccount string             `json:"self_account"`
	Account     string             `json:"account"`
	ID          int64              `json:"id"`
	UserRole    model.UserRoleType `json:"user_role"`
	jwt.RegisteredClaims
}

type RefreshClaims struct {
	Account string `json:"account"`
	ID      int64  `json:"id"`
	jwt.RegisteredClaims
}

// TokenResponse token响应结构
type TokenResponse struct {
	AccessToken  string `json:"access_token"`
	RefreshToken string `json:"refresh_token"`
	TokenType    string `json:"token_type"`
}

// GenerateTokens 生成access token和refresh token
func GenerateTokens(user *model.User) (*TokenResponse, error) {
	// 生成access token
	accessToken, err := generateAccessToken(user)
	if err != nil {
		return nil, err
	}

	// 生成refresh token
	refreshToken, err := generateRefreshToken(user)
	if err != nil {
		return nil, err
	}

	return &TokenResponse{
		AccessToken:  accessToken,
		RefreshToken: refreshToken,
		TokenType:    "bearer",
	}, nil
}

// generateAccessToken 生成access token
func generateAccessToken(user *model.User) (string, error) {
	// 设置过期时间
	expireDuration := time.Hour * time.Duration(config.AppConfig.JWT.ExpireTime)
	expireTime := time.Now().Add(expireDuration)

	// 创建JWT声明
	claims := AccessClaims{
		SelfAccount: user.SelfAccount,
		Account:     user.Account,
		ID:          user.Id,
		UserRole:    user.UserRole,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(expireTime),
			IssuedAt:  jwt.NewNumericDate(time.Now()),
			NotBefore: jwt.NewNumericDate(time.Now()),
			Issuer:    config.AppConfig.JWT.Issuer,
		},
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

	tokenString, err := token.SignedString([]byte(config.AppConfig.JWT.SecretKey))
	if err != nil {
		return "", err
	}

	return tokenString, nil
}

// generateRefreshToken 生成refresh token
func generateRefreshToken(user *model.User) (string, error) {
	// 设置过期时间
	expireDuration := time.Hour * time.Duration(config.AppConfig.JWT.RefreshExpireTime)
	expireTime := time.Now().Add(expireDuration)

	// 创建JWT声明
	claims := RefreshClaims{
		Account: user.Account,
		ID:      user.Id,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(expireTime),
			IssuedAt:  jwt.NewNumericDate(time.Now()),
			NotBefore: jwt.NewNumericDate(time.Now()),
			Issuer:    config.AppConfig.JWT.Issuer,
		},
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

	tokenString, err := token.SignedString([]byte(config.AppConfig.JWT.RefreshSecretKey))
	if err != nil {
		return "", err
	}

	return tokenString, nil
}

// ParseRefreshToken 解析refresh token
func ParseRefreshToken(tokenString string) (*RefreshClaims, error) {
	// 解析token
	token, err := jwt.ParseWithClaims(tokenString, &RefreshClaims{}, func(token *jwt.Token) (interface{}, error) {
		return []byte(config.AppConfig.JWT.RefreshSecretKey), nil
	})

	if err != nil {
		return nil, err
	}

	// 验证token
	if claims, ok := token.Claims.(*RefreshClaims); ok && token.Valid {
		return claims, nil
	}

	return nil, errors.New("invalid refresh token")
}

// parseAccessToken 解析access token
func ParseAccessToken(tokenString string) (*AccessClaims, error) {
	// 解析token
	token, err := jwt.ParseWithClaims(tokenString, &AccessClaims{}, func(token *jwt.Token) (interface{}, error) {
		return []byte(config.AppConfig.JWT.SecretKey), nil
	})

	if err != nil {
		return nil, err
	}

	// 验证token
	if claims, ok := token.Claims.(*AccessClaims); ok && token.Valid {
		return claims, nil
	}

	return nil, errors.New("invalid access token")
}
